package utils

import (
	"github.com/gin-gonic/gin"
	"mygo/mystruct"
	"mime/multipart"
	"strconv"
	"fmt"
	"sync"
	"bufio"
	"errors"
	"strings"
	//"net/http"
	"encoding/csv"
	"encoding/json"
	"github.com/google/uuid"
	"github.com/xuri/excelize/v2"
)


// 获取表单参数
func User_data_struct(cont *gin.Context, Body *mystruct.ModelItem, isappend bool) (map[string]interface{}, map[string]*multipart.FileHeader) {
	make_map := make(map[string]interface{})
	make_key := make(map[string]*multipart.FileHeader)
	for _, value := range Body.Data {
		switch value.Select {
			case "string":
				make_map[value.Value] = cont.PostForm(value.Value)
			case "file":
				file, err := cont.FormFile(value.Value)
				if err == nil {
					make_map[value.Value] = file.Filename
					make_key[value.Value] = file
				}else if isappend {
					make_map[value.Value] = ""
				}
			case "int":
				intValue, err := strconv.ParseInt(cont.PostForm(value.Value), 10, 64)
				if err == nil || isappend {
				    make_map[value.Value] = intValue
				}
			case "bool":
				bolvalue, err := strconv.ParseBool(cont.PostForm(value.Value))
				if err == nil || isappend {
					make_map[value.Value] = bolvalue
				}
			case "prgs":
				prsValue, err := strconv.ParseInt(cont.PostForm(value.Value), 10, 64)
				if prsValue < 0 || prsValue > 100 {
					if !isappend {
						err = errors.New("进度条设置不正确")
					}else{
						prsValue = 0
					}
				}
				if err == nil || isappend {
				    make_map[value.Value] = prsValue
				}
			case "word":
				if isappend {
					var json_data map[string]string
					json.Unmarshal([]byte(cont.PostForm(value.Value)), &json_data)
					make_map[value.Value] = map[string]string{
						"name": json_data["name"], 
						"id": uuid.New().String(), 
						"model": json_data["model"],
					}
				} else {
					make_map[value.Value] = cont.PostForm(value.Value)
				}
			default:
				make_map[value.Value] = cont.PostForm(value.Value)
		}
	}
	return make_map, make_key
}

func GetClientIP(cont *gin.Context) string {
    ip := cont.Request.Header.Get("X-Real-IP")
    if ip == "" {
        ips := cont.Request.Header.Get("X-Forwarded-For")
        if ips != "" {
            ip = strings.Split(ips, ",")[0] // 取第一个IP
        }
    }
    if ip == "" {
        ip = cont.ClientIP()
    }
    return ip
}

func StreamTXTToWriter(c *gin.Context, data [][]string, filename string, delimiter byte) error {
    // 设置响应头
    c.Header("Content-Type", "text/plain; charset=utf-8")
    c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
    
    // 使用大缓冲区+内存池
    bufWriter := bufio.NewWriterSize(c.Writer, 128*1024) // 128KB缓冲
    defer bufWriter.Flush()
    
    var (
        bufPool = sync.Pool{
            New: func() interface{} {
                return make([]byte, 0, 4096) // 4KB行缓冲
            },
        }
        rowCount int
    )
    
    for _, row := range data {
        select {
        case <-c.Request.Context().Done():
            return c.Request.Context().Err()
        default:
            // 从池中获取缓冲区
            buf := bufPool.Get().([]byte)
            buf = buf[:0]
            
            // 手动构建行（比strings.Join快30%）
            for i, field := range row {
                if i > 0 {
                    buf = append(buf, delimiter)
                }
                buf = append(buf, field...)
            }
            buf = append(buf, '\n')
            
            // 写入到网络缓冲
            if _, err := bufWriter.Write(buf); err != nil {
                bufPool.Put(buf)
                return fmt.Errorf("txt写入失败: %w", err)
            }
            
            // 每1万行强制刷新
            if rowCount++; rowCount%10000 == 0 {
                if err := bufWriter.Flush(); err != nil {
                    bufPool.Put(buf)
                    return err
                }
            }
            
            bufPool.Put(buf)
        }
    }
    return nil
}

func StreamCSVToWriter(c *gin.Context, data [][]string, filename string) error {
    // 设置响应头
    c.Header("Content-Type", "text/csv; charset=utf-8")
    c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
    
    // 使用缓冲写入器提升性能
    bufWriter := bufio.NewWriterSize(c.Writer, 64*1024) // 64KB缓冲
    defer bufWriter.Flush()
    
    csvWriter := csv.NewWriter(bufWriter)
    csvWriter.Comma = ',' // 可配置分隔符
    
    // 分批写入+连接检查
    batchSize := 5000
    for i := 0; i < len(data); {
        select {
        case <-c.Request.Context().Done():
            return c.Request.Context().Err()
        default:
            end := i + batchSize
            if end > len(data) {
                end = len(data)
            }
            
            if err := csvWriter.WriteAll(data[i:end]); err != nil {
                return fmt.Errorf("csv写入失败: %w", err)
            }
            
            // 手动刷新以触发网络发送
            csvWriter.Flush()
            if err := csvWriter.Error(); err != nil {
                return err
            }
            
            i = end
        }
    }
    return nil
}

func StreamXLSXToWriter(c *gin.Context, data [][]string, filename string) error {
    // 设置响应头
    c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
    
    // 创建Excel文件
    f := excelize.NewFile()
    defer f.Close()
    
    // 创建流式写入器
    sw, err := f.NewStreamWriter("Sheet1")
    if err != nil {
        return fmt.Errorf("创建流式写入器失败: %w", err)
    }
    
    // 设置行选项
    rowOpts := excelize.RowOpts{Height: 15, Hidden: false}
    
    // 流式写入数据
    for rowIdx, rowData := range data {
        select {
        case <-c.Request.Context().Done():
            return c.Request.Context().Err()
        default:
            // 转换数据类型
            row := make([]interface{}, len(rowData))
            for i, v := range rowData {
                row[i] = v
            }
            
            // 设置行位置
            cell, _ := excelize.CoordinatesToCellName(1, rowIdx+1)
            
            // 正确的调用方式：合并数据和选项到单个调用
            if err := sw.SetRow(cell, row, rowOpts); err != nil {
                return fmt.Errorf("写入行失败: %w", err)
            }
            
            // 每1000行刷新一次
            if rowIdx%1000 == 0 {
                if err := sw.Flush(); err != nil {
                    return fmt.Errorf("刷新失败: %w", err)
                }
            }
        }
    }
    
    // 最终刷新
    if err := sw.Flush(); err != nil {
        return err
    }
    
    // 写入HTTP响应
    if _, err := f.WriteTo(c.Writer); err != nil {
        return fmt.Errorf("写入响应失败: %w", err)
    }
    
    return nil
}